const { reject, result } = require("lodash");

const PENDING ='pending';  //等待   // 定义成常量是为了复用且代码有提示
const FULFILLED = 'fulfilled'; //成功
const REJECTED = 'reject';  //失败
class MyPromise{
    constructor(executor){//通过构造函数constructor来接收执行器  executor代表执行器
        try {
            executor(this.resolve,this.reject)
        } catch (error) {
            this.reject(error)
        }
        
    }
    status = PENDING;//promise状态
    value = undefined;//成功之后的值
    reason = undefined;//失败之后的原因
    successCallback = [];//成功回调 数组是为了同时存储多个回调
    failCallback = [];//失败回调 数组是为了同时存储多个回调

    resolve = value =>{//定义成监听函数  平台函数的this指向window或者underfind 箭头函数内部的this指向类的实例对象（promise对象）
        if(this.status !== PENDING) return// 判断如果状态不是等待 阻止执行
        this.status = FULFILLED;//状态改为成功
        this.value = value//保存成功之后的值
        // 判断成功回调是否存在 如果存在 执行调用
        // this.successCallback && this.successCallback(this.value); //非数组时
        while(this.successCallback.length) this.successCallback.shift()()
        
    }
    reject = reason =>{
        if(this.status !== PENDING) return// 判断如果状态不是等待 阻止执行
        this.status = REJECTED;//状态改为失败
        this.reason = reason;//保存失败之后的原因
        // 判断失败回调是否存在 如果存在 执行调用
        // this.failCallback && this.failCallback(this.value) //非数组时
        while(this.failCallback.length) this.failCallback.shift()();
    }
    then(successCallback,failCallback){
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : (reason) => { throw reason}
        let promise2 = new MyPromise((resolve,reject) =>{
            // 判断状态
            if (this.status == FULFILLED) {
                // setTimeout 是为了让内部执行内容异步 即promise2可获取到值
                setTimeout(() =>{
                   try {
                        // 同步时正常执行
                    let x = successCallback(this.value);
                    // 判断x的值是普通值还是promise对象
                    // 如果是普通值 直接调用resolve
                    // 通过是promise对象 查看promise对象返回的结果
                    // 根据promise对象返回的结果来决定调用resolve还是reject
                    resolvePromise(promise2,x,resolve,reject);
                    // resolve(x)
                   } catch (error) {
                       reject(error);
                   }
                },0) 
            }
            else if (this.status == REJECTED) {
                setTimeout(() =>{
                    try {
                         // 同步时正常执行
                      let x = failCallback(this.reason);
                     // 判断x的值是普通值还是promise对象
                     // 如果是普通值 直接调用resolve
                     // 通过是promise对象 查看promise对象返回的结果
                     // 根据promise对象返回的结果来决定调用resolve还是reject
                     resolvePromise(promise2,x,resolve,reject);
                     // resolve(x)
                    } catch (error) {
                        reject(error);
                    }
                 },0)
            }else{
                // 等待  
                // 异步时 将成功回调和失败回调存储起来，等待状态发生改变
                this.successCallback.push(()=>{
                    setTimeout(() =>{
                        try {
                             // 同步时正常执行
                         let x = successCallback(this.value);
                         // 判断x的值是普通值还是promise对象
                         // 如果是普通值 直接调用resolve
                         // 通过是promise对象 查看promise对象返回的结果
                         // 根据promise对象返回的结果来决定调用resolve还是reject
                         resolvePromise(promise2,x,resolve,reject);
                         // resolve(x)
                        } catch (error) {
                            reject(error);
                        }
                     },0) 
                });
                this.failCallback.push(()=>{
                    setTimeout(() =>{
                        try {
                             // 同步时正常执行
                          let x = failCallback(this.reason);
                         // 判断x的值是普通值还是promise对象
                         // 如果是普通值 直接调用resolve
                         // 通过是promise对象 查看promise对象返回的结果
                         // 根据promise对象返回的结果来决定调用resolve还是reject
                         resolvePromise(promise2,x,resolve,reject);
                         // resolve(x)
                        } catch (error) {
                            reject(error);
                        }
                     },0)
                });

            }
        })
        return promise2 //为了可以链式调用 所以返回值必须是promise对象
        

    }
    // finally 无论当前promis对象的状态如何 finally里的函数都会执行  后面可以加链式调用
    finally(callback){
        return this.then(value =>{
            return MyPromise.resolve(callback().then(()=>value));;
        },reason =>{
           
            return MyPromise.resolve(callback().then(()=>reason));;
        })
    }
    // 
    catch(failCallback){
        return this.then(undefined,failCallback)
    }
    // all 静态方法
    // all方法从左往右依次输出 无论异步同步
    static all(array){
        let result = [];
        let index = 0;
        return new MyPromise((resolve,reject) =>{
            function addData(key,value) {
                result[key] = value;
                index++
                if(index == array.length){
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if(current instanceof MyPromise){
                    // promise对象
                    current.then(value =>addData(i,value),reason =>reject(reason))
                }else{
                    // 普通值 
                    addData(i,array[i]);
                } 
            }
           
        })
    }
    // resolve 静态方法
    // resolve方法 无论参数如何(普通值还是promise对象) 都返回一个promise对象
    static resolve(value){
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve =>resolve(value))
    }
}
function resolvePromise(promise2,x,resolve,reject) {
    if(promise2 === x){
        return reject(new TypeError('Chaning cycle detected for promise #<Promise>'))
    }
    // instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
    if(x instanceof MyPromise){
        // x是promise对象
        // x.then(value =>resolve(value),reason =>reject(reason))
        // 简写
        x.then(resolve,reject);
    }else{
        // x是普通值
        resolve(x)
    }
    
}


function other() {
    return new MyPromise((resolve,reject)=>{
        resolve('other函数')
    })
}

let promise = new MyPromise((resolve,reject)=>{
    // setTimeout(()=>{
    //     resolve('成功');
    // },2000)
    // throw new Error('executor error')
    // resolve('成功');
    reject('失败')
})
// promise.then().then().then(value => console.log(value),reason => console.log(reason))
// let p1 = promise.then(value =>{
//     console.log(value);
//     // return other()
//     // throw new Error('then error');
//     return "aaa"
// },reason =>{
//     console.log(reason);
//     return 222
// }).then(value =>{
//     console.log(value,'上一个then的返回值');
// },reason =>{
//     console.log('错误了');
//     console.log(reason);
// })

// p1.then(value =>{
//     console.log(value);
// },reason =>{
//     console.log(reason.message);
    
// })
function p1() {
    return new MyPromise((resolve,reject)=>{
        setTimeout(function () {
            resolve('p1')
        },2000)
    })
}
function p2() {
    return new MyPromise((resolve,reject)=>{
        resolve('失败')
        
    })
} 

// all方法从左往右依次输出 无论异步同步
// MyPromise.all(["a","b",p1(),p2(),'c']).then(result =>console.log(result))
// resolve方法 无论参数如何(普通值还是promise对象) 都返回一个promise对象
// MyPromise.resolve(1000).then(value =>console.log(value))
// MyPromise.resolve(p1()).then(value =>console.log(value))
// finally 无论当前promis对象的状态如何 finally里的函数都会执行  后面可以加链式调用
// p2().finally(() =>{
//     console.log('2332323233');
//     return p1();
// }).then(value =>{
//     console.log(value);
// },reason =>{
//     console.log(reason);
// })
p2().then(value =>console.log(value)).catch(reason => console.log(reason))